package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;
	@Autowired
	private TrackStatMapper trackStatMapper;
	@Autowired
	private AlbumInfoMapper albumInfoMapper;
	@Autowired
	private VodService vodService;
	@Autowired
	private RedisTemplate redisTemplate;
	@Override
	public Page<TrackListVo> findUserTrackPage(Page<TrackListVo> trackListVoPage, Long userId, TrackInfoQuery trackInfoQuery) {
		return baseMapper.findUserTrackPage(trackListVoPage,userId,trackInfoQuery);
	}

	@Override
	public void saveTrackInfo(Long userId, TrackInfoVo trackInfoVo) {
		TrackInfo trackInfo = BeanUtil.copyProperties(trackInfoVo, TrackInfo.class);
		trackInfo.setUserId(userId);
		trackInfo.setSource("1");
		trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
		//1.3 根据专辑ID查询专辑信息得到专辑已有声音数量，计算出新增声音序号
		AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
		trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
		//1.4 根据文件唯一标识远程调用腾讯点播平台接口获取音频文件信息（音频时长、大小、音频类型）
		TrackMediaInfoVo trackMediaInfoVo = vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId());
		if (trackMediaInfoVo != null) {
			trackInfo.setMediaDuration(new BigDecimal(trackMediaInfoVo.getDuration()));
			trackInfo.setMediaSize(trackMediaInfoVo.getSize());
			trackInfo.setMediaType(trackMediaInfoVo.getType());
		}
		//1.5 保存声音得到声音ID

		baseMapper.insert(trackInfo);
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY,0);
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT,0);
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE,0);
		this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT,0);

		//3.更新专辑包含声音数量
		albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount()+1);
		albumInfoMapper.updateById(albumInfo);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateTrackInfo(Long id, TrackInfoVo trackInfoVo) {
		//更新声音数据 需要拿到声音数据 比较我们上传的声音数据的唯一标识是否相等 相等只需要修改声音表及统计表数据
		//不相等就需要将此次的声音数据填入我们声音表中 并将云点播平台中之前的·声音数据进行删除
		TrackInfo trackInfo = baseMapper.selectById(id);
		BeanUtil.copyProperties(trackInfoVo, trackInfo);
		String beformMediaFileId = trackInfo.getMediaFileId();
		String afterMediaFileId = trackInfoVo.getMediaFileId();





		if (!afterMediaFileId.equals(beformMediaFileId)){
			TrackMediaInfoVo trackMediaInfo = vodService.getTrackMediaInfo(afterMediaFileId);
			Assert.notNull(trackMediaInfo,"无法在云点播中获取到声音数据");
			trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfo.getDuration()));
			trackInfo.setMediaType(trackMediaInfo.getType());
			trackInfo.setMediaSize(trackMediaInfo.getSize());
			vodService.deleteTrackMedia(trackInfo.getMediaFileId());
		}
		trackInfo.setUpdateTime(new Date());
		baseMapper.updateById(trackInfo);

	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void removeTrackInfo(Long id) {
		//删除声音数据需要删除声音表中的数据 统计表中的数据 云点播中的数据 更新专辑中所剩声音的数量 -1
		//获取原数据 后续操作需要原数据字段
		TrackInfo trackInfo = baseMapper.selectById(id);
		//根据原数据中的专辑ID去修改对应专辑的声音数据的序号
		baseMapper.updateTrackNum(trackInfo.getAlbumId(),trackInfo.getOrderNum());
		//删除与元数据对应的统计数据
		trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId,id));
		//删除原数据
		baseMapper.delete(new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getId,id));
		//根据原数据拿到对应的专辑数据 修改专辑中的声音总数
		AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
		albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
		albumInfoMapper.updateById(albumInfo);
		//删除云点播中原声音数据
		vodService.deleteTrackMedia(trackInfo.getMediaFileId());
	}

	@Autowired
	private UserFeignClient userFeignClient;

	/**
	 * 分页获取专辑下声音列表，动态根据用户情况展示声音付费标识
	 *
	 * @param userId   用户ID
	 * @param albumId  专辑ID
	 * @param pageInfo 分页对象
	 * @return
	 */
	@Override
	public Page<AlbumTrackListVo> getAlbumTrackPage(Page<AlbumTrackListVo> pageInfo, Long albumId,Long userId ) {
		//1.根据专辑ID分页获取该专辑下包含声音列表（包含声音统计信息）-默认声音付费标识为false
		pageInfo = albumInfoMapper.getAlbumTrackPage(pageInfo, albumId);
		//2.TODO 动态判断当前页中每个声音付费标识 关键点：找出付费情况
		//2.根据专辑ID查询专辑信息
		AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
		Assert.notNull(albumInfo, "专辑："+albumId+"不存在");
		String payType = albumInfo.getPayType();

		//3.处理用户未登录情况
		if (userId == null) {
			//3.1 判断专辑付费类型：VIP免费（0102）或 付费（0103） 除了免费试听外声音都应该设置付费标识
			if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType)|| SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
				//3.2 获取本页中声音列表，过滤将声音序号大于免费试听集数声音付费标识设置为true
				pageInfo.getRecords()
						.stream()
						.filter(albumTrackVo -> albumTrackVo.getOrderNum() > albumInfo.getTracksForFree()) //过滤获取除免费试听以外声音
						.collect(Collectors.toList())
						.stream().forEach(albumTrackListVo -> {
							albumTrackListVo.setIsShowPaidMark(true);
						});
			}
		} else {
			//4.处理用户已登录情况
			//4.1 远程调用用户服务获取用户信息得到用户身份
			UserInfoVo userInfoVo = userFeignClient.getUserVoById(userId).getData();
			Assert.notNull(userInfoVo, "用户"+userId+"不存在");
			Integer isVip = userInfoVo.getIsVip();

			//4.2 默认设置需要进一步确定购买情况标识：默认false
			Boolean isNeedCheckPayStatus = false;

			//4.2.1 如果专辑付费类型 VIP免费
			if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType)) {
				//当前用户为普通用户或VIP会员过期
				if (isVip.intValue() == 0) {
					isNeedCheckPayStatus = true;
				}
				if (isVip.intValue() == 1 && new Date().after(userInfoVo.getVipExpireTime())) {
					isNeedCheckPayStatus = true;
				}
			}
			//4.2.2 如果专辑付费类型 付费
			if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
				//当前用户为普通用户或VIP会员过期
				isNeedCheckPayStatus = true;
			}
			if (isNeedCheckPayStatus) {
				//4.3 进一步确定用户是否购买专辑或声音-远程调用用户服务获取本页中专辑或者声音购买情况
				//本页中需要检查购买情况声音列表，过滤掉当前页免费试听声音
				List<AlbumTrackListVo> needCheckTrackList = pageInfo.getRecords().stream()
						.filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree())
						.collect(Collectors.toList());

				//本页中需要检查购买情况声音ID列表，过滤掉当前页免费试听声音
				List<Long> needCheckTrackIdList = needCheckTrackList.stream()
						.map(albumTrackListVo -> albumTrackListVo.getTrackId())
						.collect(Collectors.toList());


				Map<Long, Integer> userPayStatusTrackMap = userFeignClient.userIsPaidTrack(userId, albumId, needCheckTrackIdList).getData();
				Assert.notNull(userPayStatusTrackMap,"获取用户支付声音记录失败");
				System.out.println(userPayStatusTrackMap);
				//4.4 循环当前页中声音列表-跟返回用户购买情况声音集合逐一判断
				needCheckTrackList.stream().forEach(needCheckTrack -> {
					Integer payStatus = userPayStatusTrackMap.get(needCheckTrack.getTrackId());
					if (payStatus.intValue() == 0) {
						//4.5 某个声音用户未购买，将设置付费标识 isShowPaidMark:true
						needCheckTrack.setIsShowPaidMark(true);
					}
				});
			}
		}
		System.out.println(pageInfo);
		return pageInfo;
	}
	@Override
	public List<TrackInfo> getCheckTrackIdList(Long trackId,Integer count){
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		Assert.notNull(trackInfo,"该声音数据不存在");
		List<TrackInfo> trackInfos = trackInfoMapper.selectList(new LambdaQueryWrapper<TrackInfo>()
				.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId())
				.ge(TrackInfo::getOrderNum, trackInfo.getOrderNum())
				.orderBy(true, true, TrackInfo::getOrderNum)
				.last(" limit "+count+ " ")
		);
		List<Long> userPaidTrackList = userFeignClient.getUserPaidTrackIdList(trackInfo.getAlbumId()).getData();
		if (CollectionUtil.isNotEmpty(userPaidTrackList)){

			trackInfos = trackInfos.stream().filter(track -> !userPaidTrackList.contains(track.getId())).collect(Collectors.toList());
		}
		return trackInfos;
	}
	@Override
	public List<Map<String,Object>>  findUserTrackPaidList(Long trackId) {
		TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
		Assert.notNull(trackInfo,"该声音数据不存在");
		AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
		Assert.notNull(trackInfo,"该专辑数据不存在");
		Map<String,Object> firstMap = new HashMap<>();
		firstMap.put("name","本集");
		firstMap.put("trackCount",1);
		firstMap.put("price",albumInfo.getPrice());
		List<TrackInfo> trackInfos = trackInfoMapper.selectList(new LambdaQueryWrapper<TrackInfo>()
				.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId())
				.ge(TrackInfo::getOrderNum, trackInfo.getOrderNum())
				.orderBy(true, true, TrackInfo::getOrderNum)
		);

		List<Long> trackList = trackInfos.stream().map(TrackInfo::getId).collect(Collectors.toList());
		List<Long> userPaidTrackList = userFeignClient.getUserPaidTrackIdList(trackInfo.getAlbumId()).getData();
		if (CollectionUtil.isNotEmpty(userPaidTrackList)){

			trackList = trackList.stream().filter(track -> !userPaidTrackList.contains(track)).collect(Collectors.toList());
		}
		List<Map<String,Object>> result = new ArrayList<>();
		int count = trackList.size();
		result.add(firstMap);
		for (int i=10;i<=50&&count>1;i+=10){
			HashMap<String, Object> map = new HashMap<>();
			if (i<count){
				map.put("name","后"+i+"集");
				map.put("trackCount",i);
				map.put("price",albumInfo.getPrice().multiply(new BigDecimal(i)));
				result.add(map);

			}
			if (i>count){
				map.put("name","后"+count+"集");
				map.put("trackCount",count);
				map.put("price",albumInfo.getPrice().multiply(new BigDecimal(count)));
				result.add(map);
				break;
			}
		}
		return result;
	}

	@Override
	public void updateTrackStat(TrackStatMqVo trackStatMqVo) {
		String key = "mq:" + trackStatMqVo.getBusinessNo();
		try {
			Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, trackStatMqVo.getBusinessNo(), 1, TimeUnit.HOURS);
			if (flag){
				String albumStatType = "";
				trackStatMapper.updateTrackStat(trackStatMqVo.getStatType(),trackStatMqVo.getTrackId(),trackStatMqVo.getCount());

				if (SystemConstant.TRACK_STAT_PLAY==trackStatMqVo.getStatType()){
					albumStatType=SystemConstant.ALBUM_STAT_PLAY;
					albumInfoMapper.updateAlbumStat(trackStatMqVo.getStatType(),trackStatMqVo.getAlbumId(),trackStatMqVo.getCount());

				}
				if (SystemConstant.TRACK_STAT_COLLECT==trackStatMqVo.getStatType()){
					albumStatType=SystemConstant.ALBUM_STAT_PLAY;
					albumInfoMapper.updateAlbumStat(trackStatMqVo.getStatType(),trackStatMqVo.getAlbumId(),trackStatMqVo.getCount());
				}
				if (SystemConstant.TRACK_STAT_PRAISE==trackStatMqVo.getStatType()){
					albumStatType=SystemConstant.ALBUM_STAT_PLAY;
					albumInfoMapper.updateAlbumStat(trackStatMqVo.getStatType(),trackStatMqVo.getAlbumId(),trackStatMqVo.getCount());
				}
				if (SystemConstant.TRACK_STAT_COMMENT==trackStatMqVo.getStatType()){
					albumStatType=SystemConstant.ALBUM_STAT_PLAY;
					albumInfoMapper.updateAlbumStat(trackStatMqVo.getStatType(),trackStatMqVo.getAlbumId(),trackStatMqVo.getCount());
				}
			}
		} catch (Exception e) {
			// 使用 Lua 脚本安全释放锁（仅删除自己的锁）
			String luaScript =
					"if redis.call('get', KEYS[1]) == ARGV[1] then " +
							"   return redis.call('del', KEYS[1]) " +
							"else " +
							"   return 0 " +
							"end";
			redisTemplate.execute(
					new DefaultRedisScript<>(luaScript, Long.class),
					Collections.singletonList(key),
					trackStatMqVo.getBusinessNo()
			);

			throw new RuntimeException(e);
		}
	}

	private void saveTrackStat(Long trackId,String statType,Integer statNum){
		TrackStat trackStat = new TrackStat();
		trackStat.setTrackId(trackId);
		trackStat.setStatType(statType);
		trackStat.setStatNum(statNum);
		trackStatMapper.insert(trackStat);
	}
}
